var world;
var pause=false;     
function init() {
   var   b2Vec2 = Box2D.Common.Math.b2Vec2
    ,  b2AABB = Box2D.Collision.b2AABB
    , b2BodyDef = Box2D.Dynamics.b2BodyDef
    , b2Body = Box2D.Dynamics.b2Body
    , b2FixtureDef = Box2D.Dynamics.b2FixtureDef
    , b2Fixture = Box2D.Dynamics.b2Fixture
    , b2World = Box2D.Dynamics.b2World
    , b2MassData = Box2D.Collision.Shapes.b2MassData
    , b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
    , b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
    , b2DebugDraw = Box2D.Dynamics.b2DebugDraw
    ,  b2MouseJointDef =  Box2D.Dynamics.Joints.b2MouseJointDef
    ,  b2RevoluteJointDef = Box2D.Dynamics.Joints.b2RevoluteJointDef
      ;
   
   world = new b2World(
         new b2Vec2(0, 10)    //gravity
      ,  true                 //allow sleep
   );
   
   var fixDef = new b2FixtureDef;
   fixDef.density = 1.0;
   fixDef.friction = 0.5;
   fixDef.restitution = 0.2;
   
   var bodyDef = new b2BodyDef;
   
   //create ground
   bodyDef.type = b2Body.b2_staticBody;
   bodyDef.position.x = 20;
   bodyDef.position.y = 18;
   fixDef.shape = new b2PolygonShape;
   fixDef.shape.SetAsBox(30, 0.5);
   var ground = world.CreateBody(bodyDef);
   ground.CreateFixture(fixDef);

   bodyDef.position.Set(10, -1);
   world.CreateBody(bodyDef).CreateFixture(fixDef);
   fixDef.shape.SetAsBox(2, 10);
   bodyDef.position.Set(-1.8, 8);
   world.CreateBody(bodyDef).CreateFixture(fixDef);
   bodyDef.position.Set(44, 13);
   world.CreateBody(bodyDef).CreateFixture(fixDef);
   
   //create some objects
   bodyDef.type = b2Body.b2_dynamicBody;
   //draw center box
   fixDef.shape = new b2PolygonShape;
   bodyDef.position.x = 28;
   bodyDef.position.y = 11.5;
   fixDef.shape.SetAsBox(0.5, 6);
   world.CreateBody(bodyDef).CreateFixture(fixDef);

   //draw upper box
   fixDef.shape = new b2PolygonShape;
   fixDef.shape.SetAsBox(3.0, 0.3);
   bodyDef.position.x = 28;
   bodyDef.position.y = 5.2;
   world.CreateBody(bodyDef).CreateFixture(fixDef);
   for(var i=0; i<6; i++){
      fixDef.shape = new b2CircleShape(0.5);       
      bodyDef.position.x = 25.5+1*i;
      bodyDef.position.y = 4.4;
      var egg= world.CreateBody(bodyDef);        
      egg.CreateFixture(fixDef);
   }
            
   //draw fly egg  
   fixDef.shape = new b2CircleShape(1.0);       
   bodyDef.position.x = 6;
   bodyDef.position.y = 0;
   var flyegg= world.CreateBody(bodyDef);        
   flyegg.CreateFixture(fixDef);

   //draw drop egg  
   fixDef.shape = new b2CircleShape(1.5);       
   bodyDef.position.x = 15;
   bodyDef.position.y = 0;
   var dropegg1= world.CreateBody(bodyDef);        
   dropegg1.CreateFixture(fixDef);

   fixDef.shape = new b2CircleShape(1.5);       
   bodyDef.position.x = 18;
   bodyDef.position.y = 5;
   var dropegg2= world.CreateBody(bodyDef);        
   dropegg2.CreateFixture(fixDef);

   //draw destination box
   bodyDef.type = b2Body.b2_staticBody;
   fixDef.shape=new b2PolygonShape;
   fixDef.shape.SetAsBox(2.4,0.3);
   bodyDef.position.x=25.0;
   bodyDef.position.y=17.2;
   world.CreateBody(bodyDef).CreateFixture(fixDef);
   fixDef.shape=new b2PolygonShape;
   fixDef.shape.SetAsBox(0.3,1);
   bodyDef.position.x=22.9;
   bodyDef.position.y=15.9;
   world.CreateBody(bodyDef).CreateFixture(fixDef);
   fixDef.shape=new b2PolygonShape;
   fixDef.shape.SetAsBox(0.3,1);
   bodyDef.position.x=27.1;
   bodyDef.position.y=15.9;
   world.CreateBody(bodyDef).CreateFixture(fixDef);


   //draw hit 
   bodyDef.type = b2Body.b2_dynamicBody;
   fixDef.shape=new b2PolygonShape;
   fixDef.shape.SetAsBox(3.0,0.3);
   bodyDef.position.x = 6;
   bodyDef.position.y = 13;
   var hit=world.CreateBody(bodyDef);
   hit.CreateFixture(fixDef);

   var revoluteJointDef = new  b2RevoluteJointDef();  
   revoluteJointDef.Initialize(hit, world.GetGroundBody(), hit.GetWorldCenter());  
   revoluteJointDef.maxMotorTorque = 1.0;
   revoluteJointDef.enableMotor = true;        
   world.CreateJoint(revoluteJointDef);

   //setup debug draw
    var debugDraw = new b2DebugDraw();
    debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));
    debugDraw.SetDrawScale(30.0);
    debugDraw.SetFillAlpha(0.3);
    debugDraw.SetLineThickness(1.0);
    debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
    world.SetDebugDraw(debugDraw);
  
    
    window.setInterval(update, 1000 / 60);
    //mouse
   
   var mouseX, mouseY, mousePVec, isMouseDown, selectedBody, mouseJoint;
   var canvasPosition = getElementPosition(document.getElementById("canvas"));
  
   document.addEventListener("mousedown", function(e) {
      isMouseDown = true;
      handleMouseMove(e);
      document.addEventListener("mousemove", handleMouseMove, true);
   }, true);
   
   document.addEventListener("mouseup", function() {
      document.removeEventListener("mousemove", handleMouseMove, true);
      isMouseDown = false;
      mouseX = undefined;
      mouseY = undefined;
   }, true);
   
   //work on mobile devices
   document.addEventListener('touchstart', function(event) {
    isMouseDown = true;
    var touch = event.touches[0];
    mouseX = (touch.pageX - canvasPosition.x) / 30;
    mouseY = (touch.pageY - canvasPosition.y) / 30;   
    }, false);

    document.addEventListener('touchend', function(event) {
    isMouseDown = false;
    mouseX = undefined;
    mouseY = undefined;   
    }, false);

    document.addEventListener('touchmove', function(event) {
    event.preventDefault();
    var touch = event.touches[0];
    mouseX = (touch.pageX - canvasPosition.x) / 30;
    mouseY = (touch.pageY - canvasPosition.y) / 30;    
    }, false);

   function handleMouseMove(e) {
      mouseX = (e.clientX - canvasPosition.x) / 30;
      mouseY = (e.clientY - canvasPosition.y) / 30;
   };

   function getBodyAtMouse() {
      mousePVec = new b2Vec2(mouseX, mouseY);
      var aabb = new b2AABB();
      aabb.lowerBound.Set(mouseX - 0.001, mouseY - 0.001);
      aabb.upperBound.Set(mouseX + 0.001, mouseY + 0.001);
      
      // Query the world for overlapping shapes.

      selectedBody = null;
      world.QueryAABB(getBodyCB, aabb);
      return selectedBody;
   }

    function getBodyCB(fixture) {
      if(fixture.GetBody().GetType() != b2Body.b2_staticBody && fixture.GetBody()==hit ){
         if(fixture.GetShape().TestPoint(fixture.GetBody().GetTransform(), mousePVec)) {
            selectedBody = fixture.GetBody();
            return false;
         }
      }
      
      return true;
   }

    $(Pause).bind("click", function(e){
        pause = !pause;
        var text = document.getElementById("Pause").firstChild;
        text.data = text.data == "Pause" ? "Resume" : "Pause";
        
    }); 


  function update() {

   if(isMouseDown && (!mouseJoint)) {
         var body = getBodyAtMouse();
         if(body) {
            var md = new b2MouseJointDef();
            md.bodyA = world.GetGroundBody();
            md.bodyB = body;
            md.target.Set(mouseX, mouseY);
            md.collideConnected = true;
            md.maxForce = 300.0 * body.GetMass();
            mouseJoint = world.CreateJoint(md);
            body.SetAwake(true);
      
         }
   }
   
   if(mouseJoint) {
         if(isMouseDown) {
            mouseJoint.SetTarget(new b2Vec2(mouseX, mouseY));
         } else {
            world.DestroyJoint(mouseJoint);
            mouseJoint = null;
         }
   }

   if(pause)
	      timeStep=0;
	   else
	      timeStep=1/60;
	   world.Step(
	         timeStep   //frame-rate
	      ,  10       //velocity iterations
	      ,  10       //position iterations
	   );
   world.DrawDebugData();
   world.ClearForces();
   collisionDetection();
  };

  function collisionDetection(){
        allContacts = world.GetContactList();
        for(var c = world.GetContactList(); c; c = c.GetNext()){
          var bodyA = c.GetFixtureA().GetBody();
          var bodyB = c.GetFixtureB().GetBody();
          if(bodyA==dropegg1 && bodyB==ground){            
            world.DestroyBody(dropegg1);
            fixDef.shape = new b2CircleShape(1.5);       
            bodyDef.position.x = 15;
            bodyDef.position.y = 0;
            dropegg1= world.CreateBody(bodyDef);        
            dropegg1.CreateFixture(fixDef);            
          }
          else if(bodyB==dropegg1 && bodyA==ground){
             world.DestroyBody(dropegg1);
             fixDef.shape = new b2CircleShape(1.5);       
             bodyDef.position.x = 15;
             bodyDef.position.y = 0;
             dropegg1= world.CreateBody(bodyDef);        
             dropegg1.CreateFixture(fixDef);
            
          }
          else if(bodyA==dropegg2 && bodyB==ground){
              world.DestroyBody(dropegg2);
              fixDef.shape = new b2CircleShape(1.5);       
              bodyDef.position.x = 18;
              bodyDef.position.y = 5;
              dropegg2= world.CreateBody(bodyDef);        
              dropegg2.CreateFixture(fixDef); 
          }
          else if(bodyB==dropegg2 && bodyA==ground){
              world.DestroyBody(dropegg2);
              fixDef.shape = new b2CircleShape(1.5);       
              bodyDef.position.x = 18;
              bodyDef.position.y = 5;
              dropegg2= world.CreateBody(bodyDef);        
              dropegg2.CreateFixture(fixDef); 
          }

        }
  }

  //helpers
   
   //http://js-tut.aardon.de/js-tut/tutorial/position.html
   function getElementPosition(element) {
      var elem=element, tagname="", x=0, y=0;
     
      while((typeof(elem) == "object") && (typeof(elem.tagName) != "undefined")) {
         y += elem.offsetTop;
         x += elem.offsetLeft;
         tagname = elem.tagName.toUpperCase();

         if(tagname == "BODY")
            elem=0;

         if(typeof(elem) == "object") {
            if(typeof(elem.offsetParent) == "object")
               elem = elem.offsetParent;
         }
      }

      return {x: x, y: y};
   }


};